// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBAPI.h"

#include "DataStructure/Input/Element/CFASTData.h"
#include "DataStructure/Input/Element/CWELDData.h"
#include "DataStructure/Input/Element/ElementTypes.h"

#include "DBManager/IService/Input/Constraint/IConstraintSummaryService.h"
#include "DBManager/IService/Input/Constraint/IRElementSummaryService.h"
#include "DBManager/IService/Input/Coordinate/ICORDSummaryService.h"
#include "DBManager/IService/Input/Dynamic/IDynamicSummaryService.h"
#include "DBManager/IService/Input/Element/IElementService.h"
#include "DBManager/IService/Input/Element/IPartitionElementCacheService.h"
#include "DBManager/IService/Input/Load/ILoadSummaryService.h"
#include "DBManager/IService/Input/Material/IMaterialSummaryService.h"
#include "DBManager/IService/Input/Node/INodeService.h"
#include "DBManager/IService/Input/Property/IPropertySummaryService.h"
#include "DBManager/IService/Input/Subcase/ISubcaseService.h"
#include "DBManager/IService/Input/Table/ITableSummaryService.h"

using namespace SG::DataStructure::Common;
using namespace SG::DBManager;

std::vector<SG::DataStructure::Common::Id> SG::DBManager::DBAPI::GetAllNodeId (DBServiceFactory* const dbm)
{
    // 获取Service
    auto nodeService    = dbm->get<INodeService> ();
    auto elementService = dbm->get<IElementService> ();

    // 返回结果
    std::vector<Id> result = nodeService->GetAllId ();

    std::set<Id> virtualNodeSet;  // 用于存储虚节点ID

    // 获取所有cweld数据，如果cweld数据内的m_g[2]有大于1e+6的结果，将其添加在result中
    for (const auto& cweld : elementService->GetAllData<SG::DataStructure::FEM::CWELDData> ())
    {
        for (size_t i = 0; i < 2; i++)
        {
            if (cweld.m_g[i] > VIRTUAL_GRID_ID_ORIGIN)
            {
                virtualNodeSet.insert (cweld.m_g[i]);
            }
        }
    }

    // 获取 所有 CFAST单元虚拟节点数据, 查找其中虚节点
    for (const auto& cfast : elementService->GetAllData<SG::DataStructure::FEM::CFASTData> ())
    {
        for (size_t i = 0; i < 2; i++)
        {
            if (cfast.m_g[i] > VIRTUAL_GRID_ID_ORIGIN)
            {
                virtualNodeSet.insert (cfast.m_g[i]);
            }
        }

        for (size_t i = 0; i < 8; i++)
        {
            if (cfast.m_gh[i] > VIRTUAL_GRID_ID_ORIGIN)
            {
                virtualNodeSet.insert (cfast.m_gh[i]);
            }
        }
    }
    // 将虚节点ID添加到结果中
    result.insert (result.end (), virtualNodeSet.begin (), virtualNodeSet.end ());

    return result;
}
/*
SG::DataStructure::Common::Status DBAPI::CopyData (DBServiceFactory* const                    src,
                                                   DBServiceFactory* const                    dest,
                                                   SG::DataStructure::Common::DataTableType   dt,
                                                   std::vector<SG::DataStructure::Common::Id> id)
{
    // 源与目标不能相同
    if (src == dest)
    {
        return SG::DataStructure::Common::Status::STATUS_Failure;
    }

    switch (dt)
    {
    case DataTableType::DT_CONSTRAINT: {
        return src->get<IConstraintSummaryService> ()->CopyData (dest, id);
        break;
    }
    case DataTableType::DT_COORDINATE: {
        return src->get<ICORDSummaryService> ()->CopyData (dest, id);
        break;
    }
    case DataTableType::DT_ELEMENT: {
        // return src->get<IElementService> ()->CopyData (dest, id);
        throw std::runtime_error ("CopyData for Element is not implemented yet.");
        break;
    }
    case DataTableType::DT_RELEMENT: {
        return src->get<IRElementSummaryService> ()->CopyData (dest, id);
        break;
    }
    case DataTableType::DT_NODE: {
        auto nodeServiceSrc = src->get<INodeService> ();

        std::vector<INodeService::ServiceDataType> datas (id.size ());

        for (size_t i = 0; i < id.size (); i++)
        {
            nodeServiceSrc->FindById (id[i], datas[i]);
        }

        auto nodeServiceDest = dest->get<INodeService> ();
        return nodeServiceDest->MAdd (datas);

        break;
    }
    case DataTableType::DT_MATERIAL: {
        return src->get<IMaterialSummaryService> ()->CopyData (dest, id);
        break;
    }
    case DataTableType::DT_PROPERTY: {
        return src->get<IPropertySummaryService> ()->CopyData (dest, id);
        break;
    }
    case DataTableType::DT_DYNAMIC: {
        return src->get<IDynamicSummaryService> ()->CopyData (dest, id);
        break;
    }
    case DataTableType::DT_LOAD: {
        return src->get<ILoadSummaryService> ()->CopyData (dest, id);
        break;
    }
    case DataTableType::DT_TABLE: {
        return src->get<ITableSummaryService> ()->CopyData (dest, id);
        break;
    }
    default:
        break;
    }

    return SG::DataStructure::Common::Status::STATUS_Failure;
}

SG::DataStructure::Common::Status DBAPI::CopySubcaseData (DBServiceFactory* const src, DBServiceFactory* const dest)
{
    return src->get<ISubcaseService> ()->CopyData (dest);
}
 */
SG::DataStructure::Common::Status
DBAPI::SavePartitionResults (DBServiceFactory* const                                                                    dbServiceFactory,
                             const std::map<SG::DataStructure::Common::Id, std::vector<SG::DataStructure::Common::Id>>& partitionResults)
{
    if (dbServiceFactory == nullptr)
    {
        return Status::STATUS_Failure;
    }

    auto partitionService = dbServiceFactory->get<IPartitionElementCacheService> ();
    if (!partitionService)
    {
        return Status::STATUS_Failure;
    }

    std::vector<TwoLayersData> cacheData;
    cacheData.reserve (partitionResults.size ());

    // 将映射关系转换为PartitionElementCache
    for (const auto& pair : partitionResults)
    {
        cacheData.emplace_back (pair.first, pair.second);
    }

    // 批量添加到数据库
    return partitionService->MAdd (cacheData);
}

std::vector<SG::DataStructure::Common::Id> DBAPI::GetPartitionElements (DBServiceFactory* const       dbServiceFactory,
                                                                        SG::DataStructure::Common::Id partitionId)
{
    if (dbServiceFactory == nullptr)
    {
        return {};
    }

    auto partitionService = dbServiceFactory->get<IPartitionElementCacheService> ();
    if (!partitionService)
    {
        return {};
    }

    return partitionService->GetElementsByPartition (partitionId);
}

void DBAPI::initPartitionData (SG::DBManager::DBServiceFactorySP& dbManager, int world_rank)
{
    // 获取当前分区的单元ID
    const IdArray allIds   = dbManager->get<IElementService> ()->GetAllElementId ();
    const IdArray eIndexes = DBAPI::GetPartitionElements (dbManager.get (), world_rank);
    IdArray       eElementIds;
    eElementIds.reserve (eIndexes.size ());
    for (auto&& index : eIndexes)
    {
        eElementIds.emplace_back (allIds[index]);
    }

    dbManager->GetDatabase ()->SetPartitionElement (eElementIds);
}
// std::map<SG::DataStructure::Common::Id, std::vector<SG::DataStructure::Common::Id>>
// DBAPI::GetAllPartitionResults (DBServiceFactory* const dbServiceFactory)
// {
//     std::map<SG::DataStructure::Common::Id, std::vector<SG::DataStructure::Common::Id>> results;

//     if (dbServiceFactory == nullptr)
//     {
//         return results;
//     }

//     auto partitionService = dbServiceFactory->get<IPartitionElementCacheService> ();
//     if (!partitionService)
//     {
//         return results;
//     }

//     // 获取所有分区数据
//     auto allPartitions = partitionService->GetAllData ();

//     // 转换为映射关系
//     for (const auto& partition : allPartitions)
//     {
//         results[partition.m_id] = std::move (partition.m_subs);
//     }

//     return results;
// }
